﻿using UnityEngine;

namespace Core
{
    public static partial class Utils
    {
        public static class Intersect
        {
            /// <summary>
            /// 判断线段与线段是否相交
            /// </summary>
            /// <param name="p1"></param>
            /// <param name="p2"></param>
            /// <param name="p3"></param>
            /// <param name="p4"></param>
            /// <param name="intersection"></param>
            /// <returns></returns>
            public static bool IsIntersectLineWithLine(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4, out Vector3 intersection)
            {
                intersection = Vector3.zero;

                var d = (p2.x - p1.x) * (p4.z - p3.z) - (p2.z - p1.z) * (p4.x - p3.x);

                if (d == 0.0f)
                {
                    return false;
                }

                var u = ((p3.x - p1.x) * (p4.z - p3.z) - (p3.z - p1.z) * (p4.x - p3.x)) / d;
                var v = ((p3.x - p1.x) * (p2.z - p1.z) - (p3.z - p1.z) * (p2.x - p1.x)) / d;

                if (u < 0.0f || u > 1.0f || v < 0.0f || v > 1.0f)
                {
                    return false;
                }

                intersection.x = p1.x + u * (p2.x - p1.x);
                intersection.z = p1.z + u * (p2.z - p1.z);

                return true;
            }

            /// <summary>
            /// 判断线段与圆是否相交
            /// </summary>
            /// <param name="p1"></param>
            /// <param name="p2"></param>
            /// <param name="center"></param>
            /// <param name="radius"></param>
            /// <returns></returns>
            public static bool IsIntersectLineWithCircle(Vector3 p1, Vector3 p2,
                Vector3 center, float radius)
            {
                p1.y = 0;
                p2.y = 0;
                center.y = 0;

                var diff1 = p1 - center;
                var diff2 = p2 - center;

                //点在园内
                var sqrRadius = radius * radius;
                if (diff1.sqrMagnitude < sqrRadius || diff2.sqrMagnitude < sqrRadius)
                {
                    return true;
                }

                //切点在圆外
                var proj_point = Vector3.Project(center - p1, p2 - p1) + p1;
                var diff3 = proj_point - center;
                if (diff3.sqrMagnitude > sqrRadius)
                {
                    return false;
                }

                //切点在线段外
                var p_c = (p1 + p2) * 0.5f;
                var diff4 = proj_point - p_c;
                var diff5 = p1 - p_c;
                if (diff4.sqrMagnitude > diff5.sqrMagnitude)
                {
                    return false;
                }

                return true;
            }

            /// <summary>
            /// 判断线段与矩形是否相交
            /// </summary>
            /// <param name="p1"></param>
            /// <param name="p2"></param>
            /// <param name="rect"></param>
            /// <returns></returns>
            public static bool IsIntersectLineWithRect(Vector3 p1, Vector3 p2, Vector3[] rect)
            {
                //点在矩形内部
                if (Math.IsInPolygon(rect, p1))
                {
                    return true;
                }

                if (Math.IsInPolygon(rect, p2))
                {
                    return true;
                }

                //线段相交
                int cnt = rect.Length;
                for (int i = 0; i < cnt - 1; i++)
                {
                    if (IsIntersectLineWithLine(p1, p2, rect[i], rect[i + 1], out _))
                    {
                        return true;
                    }
                }

                if (IsIntersectLineWithLine(p1, p2, rect[0], rect[cnt - 1], out _))
                {
                    return true;
                }

                return false;
            }

            /// <summary>
            /// 判断矩形是否相交
            /// </summary>
            /// <param name="rect1"></param>
            /// <param name="rect2"></param>
            /// <returns></returns>
            public static bool IsIntersectRectWithRect(Vector3[] rect1, Vector3[] rect2)
            {
                if (rect1 == null || rect2 == null)
                {
                    return false;
                }
                //点在矩形内部
                for (int i = 0; i < rect1.Length; i++)
                {
                    if (Math.IsInPolygon(rect2, rect1[i]))
                    {
                        return true;
                    }
                }

                for (int i = 0; i < rect2.Length; i++)
                {
                    if (Math.IsInPolygon(rect1, rect2[i]))
                    {
                        return true;
                    }
                }

                //边相交
                for (int i = 0; i < rect1.Length - 1; i++)
                {
                    if (IsIntersectLineWithRect(rect1[i], rect1[i + 1], rect2))
                    {
                        return true;
                    }
                }

                if (IsIntersectLineWithRect(rect1[0], rect1[^1], rect2))
                {
                    return true;
                }

                return false;
            }

            /// <summary>
            /// 判断矩形与圆是否相交
            /// </summary>
            /// <param name="rect1"></param>
            /// <param name="center"></param>
            /// <param name="radius"></param>
            /// <returns></returns>
            public static bool IsIntersectRectWithCircle(Vector3[] rect1,
                Vector3 center, float radius)
            {
                if (rect1 == null)
                {
                    return false;
                }
                for (int i = 0; i < rect1.Length - 1; i++)
                {
                    if (IsIntersectLineWithCircle(rect1[i], rect1[i + 1], center, radius))
                    {
                        return true;
                    }
                }

                if (IsIntersectLineWithCircle(rect1[0], rect1[^1], center, radius))
                {
                    return true;
                }

                return false;
            }

            public static bool IsIntersectPointInSector(Vector3 p,
                Vector3 center, Vector3 forward, float radius, float angle)
            {
                angle = Mathf.Clamp(angle, 0, 180);
                var p_dir = p - center;
                p_dir.y = 0;

                if (p_dir.sqrMagnitude > Mathf.Pow(radius, 2))
                {
                    return false;
                }

                p_dir.Normalize();
                var angle_offset = Vector3.Angle(forward, p_dir);
                if (angle_offset > angle * 0.5f)
                {
                    return false;
                }
                return true;
            }

            /// <summary>
            /// 判断线段与矩形是否相交
            /// </summary>
            /// <param name="p1"></param>
            /// <param name="p2"></param>
            /// <param name="center"></param>
            /// <param name="forward"></param>
            /// <param name="radius"></param>
            /// <param name="angle"></param>
            /// <returns></returns>
            public static bool IsIntersectLineWithSector(Vector3 p1, Vector3 p2,
                Vector3 center, Vector3 forward, float radius, float angle)
            {
                angle = Mathf.Clamp(angle, 0, 180);

                //点在扇形内
                if (IsIntersectPointInSector(p1, center, forward, radius, angle))
                {
                    return true;
                }

                if (IsIntersectPointInSector(p2, center, forward, radius, angle))
                {
                    return true;
                }

                var r_1 = center + Quaternion.Euler(0, angle / 2, 0) * forward.normalized * radius;
                var r_2 = center + Quaternion.Euler(0, -angle / 2, 0) * forward.normalized * radius;

                //线段与扇形的边相交
                if (IsIntersectLineWithLine(p1, p2, center, r_1, out _))
                {
                    return true;
                }

                if (IsIntersectLineWithLine(p1, p2, center, r_2, out _))
                {
                    return true;
                }

                // var proj_point = Vector3.Project(center - p1, p2 - p1) + p1;
                // //切点在扇形内
                // if (IsIntersectPointInSector(proj_point, center, forward, radius, angle) == true)
                // {
                //     return true;
                // }

                return false;
            }

            /// <summary>
            /// 判断矩形与扇形是否相交
            /// </summary>
            /// <param name="rect"></param>
            /// <param name="center"></param>
            /// <param name="forward"></param>
            /// <param name="radius"></param>
            /// <param name="angle"></param>
            /// <returns></returns>
            public static bool IsIntersectRectWithSector(Vector3[] rect,
                Vector3 center, Vector3 forward, float radius, float angle)
            {
                for (int i = 0; i < rect.Length - 1; i++)
                {
                    if (IsIntersectLineWithSector(rect[i], rect[i + 1], center, forward, radius, angle))
                    {
                        return true;
                    }
                }

                if (IsIntersectLineWithSector(rect[0], rect[^1], center, forward, radius, angle))
                {
                    return true;
                }
                return false;
            }
        }
    }
}
